﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Hive.Core.Model
{
    /// <summary>
    /// Describes how a hive is configured.
    /// </summary>
    public class HiveConfiguration : Configuration
    {
        private const string SourceRepositoryKey = "SourceRepository";
        private const string BinaryRepositoryKey = "BinaryRepository";

        private readonly SourceRepositoryConfiguration sourceRepositoryConfiguration;
        private readonly BinaryRepositoryConfiguration binaryRepositoryConfiguration;

        /// <summary>
        /// Creates a hive configuration.
        /// </summary>
        /// <param name="sourceRepositoryConfiguration">The source repository descriptor.</param>
        /// <param name="binaryRepositoryConfiguration">The binary repository descriptor.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="sourceRepositoryConfiguration"/>
        /// or <paramref name="binaryRepositoryConfiguration"/> is null.</exception>
        public HiveConfiguration(SourceRepositoryConfiguration sourceRepositoryConfiguration,
            BinaryRepositoryConfiguration binaryRepositoryConfiguration)
        {
            if (sourceRepositoryConfiguration == null)
                throw new ArgumentNullException("sourceRepositoryConfiguration");
            if (binaryRepositoryConfiguration == null)
                throw new ArgumentNullException("binaryRepositoryConfiguration");

            this.sourceRepositoryConfiguration = sourceRepositoryConfiguration;
            this.binaryRepositoryConfiguration = binaryRepositoryConfiguration;
        }

        /// <summary>
        /// Creates a hive configuration from a descriptor.
        /// </summary>
        /// <param name="descriptor">The descriptor.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="descriptor"/> is null.</exception>
        public HiveConfiguration(Descriptor descriptor)
            : base(descriptor)
        {
            // HACK: Need to be able to deal with different types of repositories later.

            Descriptor sourceRepositoryDescriptor = descriptor.GetChildren(SourceRepositoryKey).SingleOrDefault();
            if (sourceRepositoryDescriptor == null)
                throw new HiveException("Missing source repository descriptor.");
            sourceRepositoryConfiguration = new SubversionSourceRepositoryConfiguration(sourceRepositoryDescriptor);

            Descriptor binaryRepositoryDescriptor = descriptor.GetChildren(BinaryRepositoryKey).SingleOrDefault();
            if (binaryRepositoryDescriptor == null)
                throw new HiveException("Missing binary repository descriptor.");
            binaryRepositoryConfiguration = new ArchivedBinaryRepositoryConfiguration(binaryRepositoryDescriptor);
        }

        /// <summary>
        /// Gets the source repository configuration.
        /// </summary>
        public SourceRepositoryConfiguration SourceRepositoryConfiguration
        {
            get { return sourceRepositoryConfiguration; }
        }

        /// <summary>
        /// Gets the binary repository configuration.
        /// </summary>
        public BinaryRepositoryConfiguration BinaryRepositoryConfiguration
        {
            get { return binaryRepositoryConfiguration; }
        }

        /// <inheritdoc />
        protected override void PopulateDescriptor(Descriptor descriptor)
        {
            base.PopulateDescriptor(descriptor);

            descriptor.AddChild(SourceRepositoryKey, sourceRepositoryConfiguration.ToDescriptor());
            descriptor.AddChild(BinaryRepositoryKey, binaryRepositoryConfiguration.ToDescriptor());
        }

        /// <inheritdoc />
        protected override Configuration CreateInstanceOfSameType(Descriptor descriptor)
        {
            return new HiveConfiguration(descriptor);
        }
    }
}
